package smlab.astar
{
    import flash.display.*;
    import flash.utils.*;
  
    public class DepthManager extends Object
    {
        private var depths:Dictionary;
        private static var managers:Dictionary;

        public function DepthManager()
        {
            depths = new Dictionary(true);
            return;
        }

        public function setDepth(child:DisplayObject, d:Number) : void
        {
            depths[child] = d;
            return;
        }

        private function countDepth(child:DisplayObject, index:int, n:Number = 0) : Number
        {
            if (depths[child] == null)
            {
                if (index == 0)
                {
                    return 0;
                }
                return countDepth(child.parent.getChildAt((index - 1)), (index - 1), (n + 1));
            }
            else
            {
                return depths[child] + n;
            }
        }

        public function swapChildDepth(child:DisplayObject, depth:Number) : int
        {
            var _loc_12:int = 0;
            var _loc_13:Number = NaN;
            var _loc_3:* = child.parent;
            if (_loc_3 == null)
            {
                throw new Error("child is not in a container!!");
            }
            var _loc_4:* = _loc_3.getChildIndex(child);
            var _loc_5:* = getDepth(child);
            if (depth == _loc_5)
            {
                setDepth(child, depth);
                return _loc_4;
            }
            var _loc_6:* = _loc_3.numChildren;
            if (_loc_6 < 2)
            {
                setDepth(child, depth);
                return _loc_4;
            }
            if (depth < getDepth(_loc_3.getChildAt(0)))
            {
                _loc_3.setChildIndex(child, 0);
                setDepth(child, depth);
                return 0;
            }
            if (depth >= getDepth(_loc_3.getChildAt((_loc_6 - 1))))
            {
                _loc_3.setChildIndex(child, (_loc_6 - 1));
                setDepth(child, depth);
                return (_loc_6 - 1);
            }
            var _loc_7:int = 0;
            var _loc_8:* = _loc_6 - 1;
            if (depth > _loc_5)
            {
                _loc_7 = _loc_4;
                _loc_8 = _loc_6 - 1;
            }
            else
            {
                _loc_7 = 0;
                _loc_8 = _loc_4;
            }
            while (_loc_8 > (_loc_7 + 1))
            {
                
                _loc_12 = _loc_7 + (_loc_8 - _loc_7) / 2;
                _loc_13 = getDepth(_loc_3.getChildAt(_loc_12));
                if (_loc_13 > depth)
                {
                    _loc_8 = _loc_12;
                    continue;
                }
                if (_loc_13 < depth)
                {
                    _loc_7 = _loc_12;
                    continue;
                }
                _loc_3.setChildIndex(child, _loc_12);
                setDepth(child, depth);
                return _loc_12;
            }
            var _loc_9:* = getDepth(_loc_3.getChildAt(_loc_7));
            var _loc_10:* = getDepth(_loc_3.getChildAt(_loc_8));
            var _loc_11:int = 0;
            if (depth >= _loc_10)
            {
                if (_loc_4 <= _loc_8)
                {
                    _loc_11 = Math.min(_loc_8, (_loc_6 - 1));
                }
                else
                {
                    _loc_11 = Math.min((_loc_8 + 1), (_loc_6 - 1));
                }
            }
            else if (depth < _loc_9)
            {
                if (_loc_4 < _loc_7)
                {
                    _loc_11 = Math.max((_loc_7 - 1), 0);
                }
                else
                {
                    _loc_11 = _loc_7;
                }
            }
            else if (_loc_4 <= _loc_7)
            {
                _loc_11 = _loc_7;
            }
            else
            {
                _loc_11 = Math.min((_loc_7 + 1), (_loc_6 - 1));
            }
            _loc_3.setChildIndex(child, _loc_11);
            setDepth(child, depth);
            return _loc_11;
        }

        public function getDepth(child:DisplayObject) : Number
        {
            if (depths[child] == null)
            {
                return countDepth(child, child.parent.getChildIndex(child), 0);
            }
            return depths[child];
        }

        public static function swapDepth(child:DisplayObject, depth:Number) : int
        {
            return getManager(child.parent).swapChildDepth(child, depth);
        }

        public static function swapDepthAll(doc:DisplayObjectContainer) : void
        {
            var dm:DepthManager;
            var child:DisplayObject;
            var i:int;
            var doc:* = doc;
            dm = getManager(doc);
            var len:* = doc.numChildren;
            var arr:Array;
            i;
            while (i < len)
            {
                
                child = doc.getChildAt(i);
                arr.push(child);
                i = (i + 1);
            }
            arr.sortOn("y", Array.NUMERIC);
            arr.forEach(function (item:DisplayObject, index:int, array:Array) : void
            {
                doc.setChildIndex(item, index);
                dm.setDepth(item, item.y);
                return;
            }
            );
            arr;
            return;
        }

        public static function clearAll() : void
        {
            managers = null;
            return;
        }

        public static function getManager(container:DisplayObjectContainer) : DepthManager
        {
            if (!managers)
            {
                managers = new Dictionary(true);
            }
            var _loc_2:* = managers[container];
            if (!_loc_2)
            {
                _loc_2 = new DepthManager;
                managers[container] = _loc_2;
            }
            return _loc_2;
        }

        public static function bringToBottom(mc:DisplayObject) : void
        {
            var _loc_2:* = mc.parent;
            if (_loc_2 == null)
            {
                return;
            }
            if (_loc_2.getChildIndex(mc) != 0)
            {
                _loc_2.setChildIndex(mc, 0);
            }
            return;
        }

        public static function clear(container:DisplayObjectContainer) : void
        {
            delete managers[container];
            return;
        }

        public static function bringToTop(mc:DisplayObject) : void
        {
            var _loc_2:* = mc.parent;
            if (_loc_2 == null)
            {
                return;
            }
            _loc_2.addChild(mc);
            return;
        }

    }
}
